
  React={}




  React.createElement= function (tag, attrs, ...childrens) {
    return {
      tag, // 外层标签
      attrs, // 属性 是一个对象
      childrens // 是一个数组
    };
  }

  ReactDOM ={}


ReactDOM.render=function render(vnode, container, dom) {
    return container.appendChild(_render(vnode));
}


function _render(vnode) {
  if (vnode === undefined || vnode === null || typeof vnode === 'boolean') vnode = '';

  if (typeof vnode === 'number') vnode = String(vnode)
  // 如果vnode是字符串
  if (typeof vnode === 'string') {
    // 创建文本节点
    return document.createTextNode(vnode);
  }

  // 如果这个tag是函数，则渲染这个组件 react 函数就是一个组件
  if (typeof vnode.tag === 'function') {
    // 1.创建组件
    const comp = createComponent(vnode.tag, vnode.attrs);
    // 2.设置组件的属性
    setComponentProps(comp, vnode.attrs);
    console.log(comp, '1');

    // 3.组件渲染的节点对象返回
    return comp.base;
  }

  // 否则就是一个虚拟DOM对象
  const {
    tag,
    attrs
  } = vnode;
  // 创建节点对象
  const dom = document.createElement(tag);

  if (attrs) {
    // 有属性 key: className='active' title='123'
    Object.keys(attrs).forEach((key) => {
      const value = attrs[key]
      setAttribute(dom, key, value)
    })
  }

  if (vnode.childrens) {
    // 递归渲染子节点 
    vnode.childrens.forEach((child) => {
      render(child, dom);
    })
  }
  return dom;
}







/**
 * 1. 异步更新state 短时间内把多个setState合并成一个(队列: 先进先出);
 * 2. 一段时间之后，循环清空队列，渲染组件
 */
const setStateQueue = [];

function defer(fn) {
  return Promise.resolve().then(fn)
}
// 保存当前的组件

const renderQueue = [];
function enqueueSetState(stateChange, component) {
  if (setStateQueue.length === 0) {
    defer(flush);
  }
  // 1.短时间内合并多个setState
  setStateQueue.push({
    stateChange,
    component
  })
  // 如果renderQueue里面没有组件，添加到队列中、
  let r = renderQueue.some(item => {
    return item === component
  })
  if (!r) {
    // 证明是第一次添加
    renderQueue.push(component);
  }
}

// 一段时间之后
function flush() {
  let item, component;
  while (item = setStateQueue.shift()) {
    const {
      stateChange,
      component
    } = item;
    // 保存之前的状态
    if (!component.prevState) {
      component.prevState = Object.assign({}, component.state)
    }
    if (typeof stateChange === 'function') {
      // 是一个函数
      Object.assign(component.state, stateChange(component.prevState, component.props));
    } else {
      // 是一个对象
      Object.assign(component.state, stateChange);
    }

    // 赋值
    component.prevState = component.state;
  }
  while (component = renderQueue.shift()) {
    renderComponent(component);
  }
}




function render(vnode, container, dom) {
    // return diff(dom, vnode, container);
    return container.appendChild(_render(vnode));
  }




  function diff(dom, vnode, container) {
    // 对比节点的变化
    const ret = diffNode(dom, vnode);
  
    if (container) {
      container.appendChild(ret);
    }
    return ret;
  }
  
  function diffNode(dom, vnode) {
    let out = dom;
    if (vnode === undefined || vnode === null || typeof vnode === 'boolean') vnode = '';
    if (typeof vnode === 'number') vnode = String(vnode)
    // 如果vnode是字符串
    if (typeof vnode === 'string') {
      // 创建文本节点
      if (dom && dom.nodeType === 3) {
        if (dom.textContent !== vnode) {
          // 更新文本内容
          dom.textContent = vnode;
        }
      } else {
        out = document.createTextNode(vnode);
        if (dom && dom.parentNode) {
          dom.parentNode.replaceNode(out, dom);
        }
      }
      return out;
    }
    if (typeof vnode.tag === 'function') {
      return diffComponent(out, vnode);
    }
    // 非文本DOM节点
    if (!dom) {
      out = document.createElement(vnode.tag);
      // 比较子节点(dom节点和组件)
      if (vnode.childrens && vnode.childrens.length > 0 || (out.childNodes && out.childNodes.length > 0)) {
        // 对比组件或者节点
        diffChildren(out, vnode.childrens)
      }
      diffAttribute(out, vnode);
    }
    return out;
  }
  
  function diffComponent(dom, vnode) {
    let comp = dom;
    // 如果组件没有变化，重新设置props
    if (comp && comp.constructor === vnode.tag) {
      // 重新设置props
      setComponentProps(comp, vnode.attrs);
      // 赋值
      dom = comp.base;
    } else {
      // 组件类型发生变化
      if (comp) {
        // 先移除旧的组件
        unmountComponent(comp);
        comp = null;
      }
      // 1.创建新的组件
      comp = createComponent(vnode.tag, vnode.attrs);
      // 2.设置组件属性
      setComponentProps(comp.vnode.attrs)
      // 3.给当前组件挂载base
      dom = comp.base;
    }
    return dom;
  }
  
  function unmountComponent(comp) {
    removeNode(comp.base);
  }
  
  function removeNode(dom) {
    if (dom && dom.parentNode) {
      dom.parentNode.removeNode(dom);
    }
  }
  
  function diffChildren(dom, vChildren) {
    const domChildren = dom.childNodes;
    const children = [];
    const keyed = {};
  
    // 将有key的节点(用对象保存)和没有key的节点(用数组保存)分开
    if (domChildren.length > 0) {
  
    }
  
    if (vChildren && vChildren.length > 0) {
      let min = 0;
      let childrenLen = children.length;
      [...childrenLen].forEach((vchild, i) => {
        // 获取虚拟DOM中所有的key
        const key = vchild.key;
        let child;
        if (key) {
          // 如果有key，找到对应key值的节点
          if (keyed[key]) {
            child = keyed[key];
            keyed[key] = undefined;
          }
        } else if (childrenLen > min) {
          // 如果没有key，则优先找类型相同的节点
          for (let j = min; j < childrenLen; j++) {
            let c = children[j];
            if (c) {
              child = c;
              children[j] = undefined;
              if (j === childrenLen - 1) childrenLen--;
              if (j === min) min++;
              break;
            }
          }
        }
        // 对比
        child = diffNode(child, vchild);
        // 更新DOM
        const f = domChildren[i];
  
        if (child && child !== dom && child !== f) {
          // 如果更新前的对应位置为空，说明此节点是新增的
          if (!f) {
            dom.appendChild(child);
            // 如果更新后的节点和更新前对应位置的下一个节一样
          } else if (child === f.nextSibling) {
            removeNode(f);
            // 将更新后的节点移动到正确的位置
          } else {
            // 注意insertBefore的用法，第一个参数是要插入的节点；
            dom.insertBefore(child, f);
          }
        }
      })
    }
  }
  
  function diffAttribute(dom, vnode) {
    // 保存之前的DOM的所有属性
    const oldAttrs = {};
    const newAttrs = vnode.attrs;
    // dom 是原有的节点 vnod 虚拟DOM
    const domAttrs = dom.attributes;
    [...domAttrs].forEach((item) => {
      oldAttrs[item.name] = item.value;
    })
  
    // 比较
    // 如果原来的属性跟新的属性对比，不在新的属性中，则将其移除(属性值为ubdefined)
    for (let key in oldAttrs) {
      if (!(key in newAttrs)) {
        setAttribute(dom, key, undefined)
      }
    }
    //  更新 class='active' => abc
    for (let key in newAttrs) {
      if (oldAttrs[key] !== newAttrs[key]) {
        // 值不同  更新
        setAttribute(dom, key, newAttrs[key])
      }
    }
  }






  function setAttribute(dom, key, value) {
    // 将属性名clasName转换成class
    if (key === 'className') {
      key = 'class'
    }
    // 如果是一个事件 onClick onBlur
    if (/on\w+/.test(key)) {
      // 转小写
      key = key.toLowerCase();
      dom[key] = value || '';
    } else if (key === 'style') {
      // style=''
      if (!value || typeof value === 'string') {
        dom.style.cssText = value || '';
        // style={{}}
      } else if (value && typeof value === 'object') {
        // {width:20}
        for (let k in value) {
          if (typeof value[k] === 'number') {
            dom.style[k] = value[k] + 'px';
          } else {
            dom.style[k] = value[k]
          }
        }
      }
    } else {
      // 其他属性
      if (key in dom) {
        dom[key] = value || '';
      }
      if (value) {
        // 更新值 
        dom.setAttribute(key, value);
      } else {
        dom.removeAttribute(key);
      }
    }
  }

  class Component {
    constructor(props = {}) {
      this.props = props;
      this.state = {}
    }
    setState(stateChange) {
      enqueueSetState(stateChange, this);
    }
}

  function createComponent(comp, props) {
    let inst;

    console.log('组件加载了',comp);

    if (comp.prototype && comp.prototype.render) {
      console.log('类组件加载了');
      // 如果是类定义的组件 则创建这个实例 返回
      inst = new comp(props);
    } else {
      // 如果是函数组件，将函数组件扩展成类组件， 方便后边统一管理
      inst = new Component(props);
      inst.constructor = comp;
      // 定义render函数
      inst.render = function () {
        return this.constructor(props);
      }
    }
    return inst;
  }


  function setComponentProps(comp, props) {
    if (!comp.base) {
      if (comp.componentWillMount) comp.componentWillMount();
    } else if (comp.componentWillReveiveProps) {
      comp.componentWillReveiveProps();
    }
    // 设置组件属性
    comp.props = props;
    // 渲染组件
    renderComponent(comp);
  }
   function renderComponent(comp) {
    let base;
    const renderer = comp.render(); // jsx对象
    base = _render(renderer);
    if (comp.base && comp.componentWillUpdate) {
      comp.componentWillUpdate();
    }
    if (comp.base) {
      if (comp.componentDidUpdate) comp.componentDidUpdate();
    } else if (comp.componentDidMount) {
      comp.componentDidMount();
    }
    // 节点替换
    if (comp.base && comp.base.parentNode) {
      comp.base.parentNode.replaceChild(base, comp.base);
    }
    comp.base = base;
  }